package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.Constants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceDataGraphVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description DeviceServiceImpl
 * @Author zhangyadan
 * @Date 2024-09-12
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private Client client;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 同步数据
     */
    @Override
    public void syncProductList() {
        //请求参数
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);
        request.setPageSize(200);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //调用第三方查询产品列表
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //判断，如果数据为空，则中断请求
        if(!response.getBody().success){
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }
        //获取数据，存储到redis
        List<ProductVo> productVos = BeanUtil.copyToList(
                response.getBody().getData().getList().getProductInfo(),
                ProductVo.class);
        String key = CacheConstants.ALL_PRODUCT_KEY;
        redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(productVos),24, TimeUnit.HOURS);
    }

    /**
     * 查询所有产品列表
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        //从缓存中获取数据
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        //如果为空，就返回空集合
        if(StrUtil.isEmpty(jsonStr)){
            return new ArrayList<>();
        }
        //转换数据并返回
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    /**
     * 注册设备
     *
     * @param deviceDto
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //1.判断新增的设备名称是否重复
        //1.1 根据设备名称查询指定设备数量
        Integer count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());

        //1.2 判断设备数据是否大于0，大于0说明存在，抛出异常注册设备失败
        if(count>0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //2.调用阿里云IOT远程接口注册设备（接口名字：RegisterDevice）
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        //2.1 完善请求对象IotInstanceId属性，请求对象 RegisterDeviceRequest(前端已经传递封装了 ProductKey，DeviceName，Nickname)
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //2.2 执行接口
        RegisterDeviceResponse registerDeviceReponse = null;
        try {
            registerDeviceReponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("物联网接口 - 注册设备，调用失败,原因：{}",e.getMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //2.3 判断远程接口调用是否成功（Success属性）
        if(!registerDeviceReponse.getBody().success){
            log.error("物联网接口 - 注册设备，调用失败");
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //2.4 定义变量接收物联网设备的id
        String iotId = registerDeviceReponse.getBody().getData().getIotId();

        //3.调用阿里云IOT远程接口查询产品详情（QueryProduct）
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        //3.1 封装请求对象 手动封装QueryProductRequest(ProductKey,IotInstanceId)
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //3.2 执行接口
        QueryProductResponse queryProductResponse = null;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("物联网接口 - 注册设备，调用失败,原因：{}",e.getMessage());
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //3.3 判断远程接口调用是否成功（Success属性）
        if(!queryProductResponse.getBody().getSuccess()){
            log.error("物联网接口 - 注册设备，调用失败");
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //3.4 定义变量接收 产品名字
        String productName = queryProductResponse.getBody().getData().getProductName();
        //4.判断位置类型是否是绑定随身设备
        if(deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            //4.1 是，设置物理位置类型为-1
            deviceDto.setPhysicalLocationType(-1);
        }

        //5.将设备数据插入数据库
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        //5.1 完善数据，设置没有门禁，为0
        device.setHaveEntranceGuard(0);
        //5.2 完善数据，封装产品名字
        device.setProductName(productName);
        //5.3 完善数据，封装设备id
        device.setIotId(iotId);
        //5.4 插入数据库
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //5.5 插入失败（发生异常），调用阿里云IOT远程接口删除设备（DeleteDevice）
            //5.5.1 封装请求对象DeleteDeviceRequest(IotInstanceId,IotId)
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setIotId(iotId);
            try {
                //执行接口
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                log.error("物联网接口 - 注册设备，调用失败");
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
        }
    }

    /**
     * 分页查询设备列表
     *
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Page<DeviceVo> page = deviceMapper.selectByPage(devicePageQueryDto);
        return PageResponse.of(page,DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     *
     * @param request
     * @return
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        //1.调用iot查询设备详情接口获取详情数据
        //1.1 封装请求对象（IotInstanceId，其他属性request根据前端的参数封装好了）
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //1.2 执行接口
        QueryDeviceDetailResponse response;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询设备详细信息报错，原因；{}",e.getMessage());
            throw new RuntimeException("查询设备详细信息失败");
        }
        //1.3 获取详情数据
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData dataDetail = response.getBody().getData();

        //2.调用mapper根据设备id查询数据库设备数据DeviceVo
        DeviceVo deviceVo = deviceMapper.findByIotId(request.getIotId());
        //3.将IOT获取设备详情数据和数据库获取的DeviceVo数据合并(有值就覆盖没值不覆盖)
        BeanUtil.copyProperties(dataDetail,deviceVo, CopyOptions.create().ignoreNullValue());

        //4.返回数据
        return deviceVo;
    }
    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     * @param request
     * @return
     */
    @Override
    public ResponseResult selectModel(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new RuntimeException("查询设备详细信息出错");
        }
        if(!response.getBody().success){
            throw new RuntimeException("查询设备详细信息出错");
        }

        QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData data = response.getBody().getData();
        return ResponseResult.success(data);
    }

    @Override
    public ResponseResult selectrunState(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new RuntimeException("查询设备详细信息出错");
        }
        if(!response.getBody().success){
            throw new RuntimeException("查询设备详细信息出错");
        }
        QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData data = response.getBody().getData();
        return ResponseResult.success(data);
    }
    /**
     * 修改设备备注名称
     * @param deviceDto
     */
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        deviceMapper.updateDevice(device);

    }

}
